//!
/************************************************************************************************************
 * @file RBRenderPassLights.cpp
 ************************************************************************************************************/

/************************************************************************************************************
 * Precompiled Header
 ************************************************************************************************************/
#include "RBMainPCH.h"

/************************************************************************************************************
 * Includes
 ************************************************************************************************************/
#include "RBRenderPassLights.h"

#include "RBDefaultStream.h"
#include "RBEntity.h"
#include "RBLight.h"
#include "RBRenderProcess/RBEffectFactory.h"
#include "RBVertexElement.h"
#include "RBVisibilityComponent.h"

/************************************************************************************************************
 * Defines
 ************************************************************************************************************/

/************************************************************************************************************
 * Implementation
 ************************************************************************************************************/

struct SBoxVDecl
{
    float3 Pos;
    uint8  Idx[4];
};

#if 0

/************************************************************************************************************
 * Constructor
 ************************************************************************************************************/
RBRenderPassLights::RBRenderPassLights(RBCamera* pCamera, RBTexture* /*pDepth*/, RBTexture* /*pNormals*/, RBTexture* /*pDiffuse*/)
: m_uiGeometryCount(0)
, m_uiGeometryAsked(0)
{
    m_uiGeometryCount = 15;
    m_uiVertexCountPerBox = 8;
    m_uiIndexCountPerBox = 36;
    const uint32 vertexCount = m_uiVertexCountPerBox * m_uiGeometryCount;
    const uint32 indexCount = m_uiIndexCountPerBox * m_uiGeometryCount;

    RBVertexElement aElements[2];

    aElements[0] = RBVertexElement(0, RBVertexElement::VET_FLOAT3, RBVertexElement::VEU_POSITION);
    aElements[1] = RBVertexElement(0, RBVertexElement::VET_UBYTE4, RBVertexElement::VEU_BLENDINDICES);

    RBVertexDeclarationPtr spVertexDecl = RBRenderer::GetSingleton()->GetHBMgr()->CreateVertexDeclaration(aElements, 2, NULL);

    SBoxVDecl* pVertices = new SBoxVDecl[vertexCount];
    uint16* pIndices = new uint16[indexCount];

    uint32 uiVtx=0;
    uint32 uiIdx=0;
    uint16 uiIdxOffset = 0;
    for (uint32 ui=0; ui < m_uiGeometryCount; ++ui)
    {
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3(-0.5f, -0.5f, -0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3( 0.5f, -0.5f, -0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3(-0.5f,  0.5f, -0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3( 0.5f,  0.5f, -0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3(-0.5f, -0.5f,  0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3( 0.5f, -0.5f,  0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3(-0.5f,  0.5f,  0.5f);
        memset(pVertices[uiVtx].Idx, ui, 4);
        pVertices[uiVtx++].Pos = 2.0f*float3( 0.5f,  0.5f,  0.5f);

#define CREATE_TRIANGLE(a,b,c) \
        pIndices[uiIdx++] = a+uiIdxOffset; pIndices[uiIdx++] = b+uiIdxOffset; pIndices[uiIdx++] = c+uiIdxOffset

        CREATE_TRIANGLE(0,2,1); CREATE_TRIANGLE(2,3,1); // Down
        CREATE_TRIANGLE(4,5,6); CREATE_TRIANGLE(6,5,7); // Up
        CREATE_TRIANGLE(0,4,2); CREATE_TRIANGLE(2,4,6); // Left
        CREATE_TRIANGLE(1,3,5); CREATE_TRIANGLE(3,7,5); // Right
        CREATE_TRIANGLE(0,1,4); CREATE_TRIANGLE(1,5,4); // Front
        CREATE_TRIANGLE(2,6,3); CREATE_TRIANGLE(3,6,7); // Back
        uiIdxOffset += (uint16)m_uiVertexCountPerBox;
    }

    RBVertexBufferPtr spVB = RBRenderer::GetSingleton()->GetHBMgr()->CreateVertexBuffer(rb_hw_buffer_usage::HBU_DEFAULT, sizeof(SBoxVDecl), 
                                                                                        vertexCount, pVertices);
    delete[] pVertices;

    RBIndexBufferPtr spIB = RBRenderer::GetSingleton()->GetHBMgr()->CreateIndexBuffer(rb_hw_buffer_usage::HBU_DEFAULT, 
                                                                                      RBIndexBufferType::IT_16BIT, indexCount, pIndices);
    delete[] pIndices;

    m_pBoxesGeometry = RBGeometry::CreateGeometry(spVB, spVertexDecl, spIB, RBGeometryPrimitiveType::TRIANGLELIST);
/*
    m_pBoxesGeometry->GetMaterial()->GetSampler(RBMaterial::ST_SHADER0).Texture = pDepth;
    m_pBoxesGeometry->GetMaterial()->GetSampler(RBMaterial::ST_SHADER1).Texture = pNormals;
    m_pBoxesGeometry->GetMaterial()->GetSampler(RBMaterial::ST_SHADER2).Texture = pDiffuse;
*/

    Culler->SetCamera(pCamera);
    SetName("RenderPassLights");

    ClearFlags = RBRenderer::CF_COLOR | RBRenderer::CF_STENCIL;

    RBEffect* pLightsEffect = RBEffectFactory::GetSingleton()->RetrieveEffect("Lights");
    m_pBoxesGeometry->GetMaterial()->SetEffect(pLightsEffect);

    m_vPositionsAttenuation = m_pBoxesGeometry->DataContainer.AddEffectData<float4>("PositionsAttenuations",1);
    m_vColors = m_pBoxesGeometry->DataContainer.AddEffectData<float4>("Colors", 1);
}

/************************************************************************************************************
 * Destructor
 ************************************************************************************************************/
RBRenderPassLights::~RBRenderPassLights()
{

}

/***********************************************************************************************************
 * Instead of collecting geometries, we collect the lights from the scene, and replace them with an 
 * appropriate geometry
 ***********************************************************************************************************/
const RBGeometryArray& RBRenderPassLights::CollectGeometries(uint32 uiFrameID)
{
    m_uiGeometryAsked = 0;
    m_kLightsGeometries.clear();
    const RBVisibilityComponentArray& entities = Culler->GetVisibleEntities(uiFrameID);
    uint32 uiPointCount = 0;
    for (uint32 uiEntity = 0; uiEntity < entities.size(); ++uiEntity)
    {
        const RBLightComponent* pLightComponent = entities[uiEntity]->GetEntity()->GetComponent<RBLightComponent>();
        if (pLightComponent == NULL)
        {
            continue;
        }

        const RBLightArray& lights = pLightComponent->GetLights();

        for (uint32 uiLight=0; uiLight < lights.size(); ++uiLight)
        {
            const RBLight* pLight = lights[uiLight];
            if (pLight->GetType() == RBLight::LT_POINT)
            {
                if (uiPointCount == 0)
                {
                    m_kLightsGeometries.push_back(m_pBoxesGeometry);
                }

                *m_vPositionsAttenuation = float4(pLight->WorldXForm.Translate.x,
                                                  pLight->WorldXForm.Translate.y,
                                                  pLight->WorldXForm.Translate.z,
                                                  pLight->GetQuadraticAttenuation());
                *m_vColors = pLight->GetMultiplier() * float4(pLight->GetColor().r, 
                                                              pLight->GetColor().g, 
                                                              pLight->GetColor().b,1);
                ++uiPointCount;
            }
        }
    }

    m_pBoxesGeometry->GetIndexData()->IndexCount = uiPointCount * m_uiIndexCountPerBox;

    return m_kLightsGeometries;
}

#endif
/************************************************************************************************************/
